package com.yfjin.camera2;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

class Camera2Helper {


    private static final String TAG = "123123";
    private TextureView mTextureView;

    private Context context;
    private Size mPreviewSize;
    private ImageReader mImageReader;

    private HandlerThread mBackgroundThread;
    private Handler mBackgroundHandler;

    private CameraDevice mCameraDevice;
    private CaptureRequest.Builder mPreviewRequestBuilder;
    private CameraCaptureSession mCaptureSession;

    String CAMERA_POS = "0";

    private Camera2Listener camera2Listener;

    public Camera2Helper(Context context, Camera2Listener camera2Listener) {
        this.context = context;
        this.camera2Listener = camera2Listener;
    }


    public synchronized void start(TextureView textureView) throws CameraAccessException {

        mTextureView = textureView;

        CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);

        // 一般0是后置，1是前置
        CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(CAMERA_POS);

        StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

        mPreviewSize = Util.getBestSupportedSize(new ArrayList<Size>(Arrays.asList(map.getOutputSizes(SurfaceTexture.class))));

        mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight()
                , ImageFormat.YUV_420_888, 2
        );


        mBackgroundThread = new HandlerThread("cameraBackground");
        mBackgroundThread.start();

        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());

        mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                Image image = reader.acquireNextImage();
                dealData(image);
                image.close();
            }
        }, mBackgroundHandler);


        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        cameraManager.openCamera(CAMERA_POS, new CameraDevice.StateCallback() {
            @Override
            public void onOpened(@NonNull CameraDevice camera) {

                Log.i(TAG, "openCamera onOpened");

                mCameraDevice = camera;

                //建立会话
                createCameraPreviewSession();

            }

            @Override
            public void onDisconnected(@NonNull CameraDevice camera) {
                Log.i(TAG, "openCamera onDisconnected");
                camera.close();
                mCameraDevice = null;
            }

            @Override
            public void onError(@NonNull CameraDevice camera, int error) {
                Log.i(TAG, "openCamera onError");
                camera.close();
                mCameraDevice = null;
            }
        }, mBackgroundHandler);
    }


    private void createCameraPreviewSession() {
        try {
            SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
            surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            Surface surface = new Surface(surfaceTexture);
            mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mPreviewRequestBuilder.addTarget(surface);
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            mPreviewRequestBuilder.addTarget(mImageReader.getSurface());


            mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                    new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession session) {

                            if (null == mCameraDevice) {
                                Log.i(TAG, "null == mCameraDevice");
                                return;
                            }
                            mCaptureSession = session;
                            try {
                                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build()
                                        , new CameraCaptureSession.CaptureCallback() {
                                        }, mBackgroundHandler);
                            } catch (CameraAccessException e) {
                                e.printStackTrace();
                            }

                        }

                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                        }
                    }, mBackgroundHandler
            );


        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }


    private byte[] y;
    private byte[] uv;
    private byte[] vu;

    private void dealData(Image image) {

        Image.Plane[] planes = image.getPlanes();
        if (y == null) {
            //总长度-起始长度
            y = new byte[planes[0].getBuffer().limit() - planes[0].getBuffer().position()];
            uv = new byte[planes[1].getBuffer().limit() - planes[1].getBuffer().position()];
            vu = new byte[planes[2].getBuffer().limit() - planes[2].getBuffer().position()];
        }

        if (image.getPlanes()[0].getBuffer().remaining() == y.length) {
            planes[0].getBuffer().get(y);
            planes[1].getBuffer().get(uv);
            planes[2].getBuffer().get(vu);
        }

        if (camera2Listener != null) {
            //getRowStride 每行像素所占宽度
            camera2Listener.onPreview(y, uv, vu, mPreviewSize, planes[0].getRowStride());
        }
    }

    public synchronized void openCamera() {

    }


    public interface Camera2Listener {
        void onPreview(byte[] y, byte[] u, byte[] v, Size size, int stride);
    }
}
